package com.gzc.just.play.last.war.allinone.orchestration;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * 服务器启动协调器
 * 控制按依赖顺序依次启动服务器
 */
@Component
public class ServerStartupCoordinator {
    
    private static final Logger logger = LoggerFactory.getLogger(ServerStartupCoordinator.class);
    
    @Autowired
    private ServerStateManager stateManager;
    
    @Autowired
    private ServerDependencyGraph dependencyGraph;
    
    @Autowired
    private ServerHealthChecker healthChecker;
    
    private final ExecutorService executorService = Executors.newFixedThreadPool(5);
    private final Map<ServerType, CompletableFuture<Void>> startupFutures = new ConcurrentHashMap<>();
    
    /**
     * 按依赖顺序启动所有服务器
     */
    public void startServersInOrder() {
        logger.info("Starting servers in dependency order...");
        logger.info(dependencyGraph.getDependencyGraphString());
        
        // 获取并行启动组
        List<List<ServerType>> parallelGroups = dependencyGraph.getParallelGroups();
        
        logger.info("Will start servers in {} parallel groups", parallelGroups.size());
        
        // 设置状态变更监听器
        stateManager.setStateChangeListener(this::onStateChange);
        
        // 按组依次启动
        for (int i = 0; i < parallelGroups.size(); i++) {
            List<ServerType> currentGroup = parallelGroups.get(i);
            logger.info("Starting group {}: {}", i + 1, 
                       currentGroup.stream().map(ServerType::getName).reduce((a, b) -> a + ", " + b).orElse(""));
            
            startServerGroup(currentGroup);
            
            // 等待当前组所有服务器启动完成
            if (!waitForGroupCompletion(currentGroup, 60000)) { // 60秒超时
                logger.error("Failed to start all servers in group {}", i + 1);
                return;
            }
        }
        
        logger.info("All servers started successfully!");
    }
    
    /**
     * 启动一组服务器（并行）
     * @param servers 服务器列表
     */
    private void startServerGroup(List<ServerType> servers) {
        for (ServerType serverType : servers) {
            CompletableFuture<Void> startupFuture = CompletableFuture.runAsync(() -> {
                startServer(serverType);
            }, executorService);
            
            startupFutures.put(serverType, startupFuture);
        }
    }
    
    /**
     * 启动单个服务器
     * @param serverType 服务器类型
     */
    private void startServer(ServerType serverType) {
        logger.info("Starting server: {}", serverType.getName());
        
        try {
            // 检查依赖是否已准备就绪
            Map<String, ServerState> serverStates = stateManager.getAllServerStates();
            Map<ServerType, ServerState> typedStates = new HashMap<>();
            serverStates.forEach((name, state) -> {
                try {
                    ServerType type = ServerType.valueOf(name.toUpperCase() + "_SERVER");
                    typedStates.put(type, state);
                } catch (IllegalArgumentException e) {
                    // 忽略无效的服务器类型
                }
            });
            
            if (!dependencyGraph.canStart(serverType, typedStates)) {
                logger.warn("Dependencies not ready for {}, skipping start", serverType.getName());
                return;
            }
            
            // 更新状态为初始化中
            stateManager.updateServerState(serverType, ServerState.INITIALIZING);
            
            // 获取服务器Bean
            Object serverBean = stateManager.getServerBean(serverType);
            if (serverBean == null) {
                throw new RuntimeException("Server bean not found: " + serverType.getName());
            }
            
            // 更新状态为已初始化
            stateManager.updateServerState(serverType, ServerState.INITIALIZED);
            
            // 调用启动方法
            stateManager.updateServerState(serverType, ServerState.STARTING);
            
            // 使用反射调用start方法
            Method startMethod = serverBean.getClass().getMethod("start");
            startMethod.invoke(serverBean);
            
            // 更新状态为监听中
            stateManager.updateServerState(serverType, ServerState.LISTENING);
            
            // 等待端口监听完成
            logger.info("Waiting for {} to start listening on port {}", serverType.getName(), serverType.getPort());
            
            if (!healthChecker.waitForServerReady(serverType, 30000)) { // 30秒超时
                throw new RuntimeException("Server " + serverType.getName() + " failed to start listening within timeout");
            }
            
            logger.info("{} is now listening on port {}", serverType.getName(), serverType.getPort());
            
            // 更新状态为连接中
            stateManager.updateServerState(serverType, ServerState.CONNECTING);
            
            // 建立到依赖服务器的连接
            if (!establishConnections(serverType)) {
                throw new RuntimeException("Failed to establish connections for " + serverType.getName());
            }
            
            // 更新状态为已连接
            stateManager.updateServerState(serverType, ServerState.CONNECTED);
            
            // 更新状态为准备就绪
            stateManager.updateServerState(serverType, ServerState.READY);
            
            // 更新状态为运行中
            stateManager.updateServerState(serverType, ServerState.RUNNING);
            
            logger.info("Server {} started successfully", serverType.getName());
            
        } catch (Exception e) {
            logger.error("Failed to start server: {}", serverType.getName(), e);
            stateManager.updateServerState(serverType, ServerState.ERROR);
        }
    }
    
    /**
     * 建立到依赖服务器的连接
     * @param serverType 服务器类型
     * @return 是否成功建立连接
     */
    private boolean establishConnections(ServerType serverType) {
        // 这里需要根据服务器类型调用相应的连接器
        // 例如，CentralServer需要连接到LoginServer、BalanceServer和SceneServer
        
        try {
            // 由于我们在all-in-one模式下，所有服务器都在同一个进程中
            // 我们只需要确保依赖服务器已经启动即可
            // 实际的TCP连接将由各服务器的连接器负责
            
            switch (serverType) {
                case CENTRAL_SERVER:
                    // CentralServer需要连接到LoginServer、BalanceServer和SceneServer
                    logger.info("CentralServer will connect to LoginServer, BalanceServer, and SceneServer");
                    break;
                    
                case GATE_SERVER:
                    // GateServer需要连接到CentralServer
                    logger.info("GateServer will connect to CentralServer");
                    break;
                    
                case SCENE_SERVER:
                    // SceneServer需要连接到CentralServer
                    logger.info("SceneServer will connect to CentralServer");
                    break;
                    
                case LOGIN_SERVER:
                case BALANCE_SERVER:
                    // 这些服务器没有依赖，不需要连接其他服务器
                    break;
            }
            
            return true;
            
        } catch (Exception e) {
            logger.error("Failed to establish connections for {}", serverType.getName(), e);
            return false;
        }
    }
    
    /**
     * 等待服务器组启动完成
     * @param servers 服务器列表
     * @param timeout 超时时间（毫秒）
     * @return 是否成功启动
     */
    private boolean waitForGroupCompletion(List<ServerType> servers, long timeout) {
        CountDownLatch latch = new CountDownLatch(servers.size());
        
        for (ServerType serverType : servers) {
            CompletableFuture<Void> future = startupFutures.get(serverType);
            if (future != null) {
                future.whenComplete((result, throwable) -> {
                    latch.countDown();
                    if (throwable != null) {
                        logger.error("Server {} startup failed", serverType.getName(), throwable);
                    }
                });
            } else {
                latch.countDown();
            }
        }
        
        try {
            return latch.await(timeout, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            logger.warn("Interrupted while waiting for server group completion", e);
            return false;
        }
    }
    
    /**
     * 状态变更监听器
     * @param serverType 服务器类型
     * @param oldState 旧状态
     * @param newState 新状态
     */
    private void onStateChange(ServerType serverType, ServerState oldState, ServerState newState) {
        logger.debug("Server {} state changed: {} -> {}", 
                    serverType.getName(), oldState, newState);
        
        // 如果服务器进入运行状态，检查是否有可以启动的新服务器
        if (newState == ServerState.RUNNING) {
            checkForStartableServers();
        }
    }
    
    /**
     * 检查是否有可以启动的新服务器
     */
    private void checkForStartableServers() {
        Map<String, ServerState> serverStates = stateManager.getAllServerStates();
        
        for (ServerType serverType : ServerType.values()) {
            ServerState currentState = serverStates.get(serverType.getName());
            
            // 如果服务器未初始化且依赖已准备就绪，则启动它
            if (currentState == ServerState.UNINITIALIZED || currentState == ServerState.INITIALIZED) {
                // 转换为类型化的状态映射
                Map<ServerType, ServerState> typedStates = new HashMap<>();
                serverStates.forEach((name, state) -> {
                    try {
                        ServerType type = ServerType.valueOf(name.toUpperCase() + "_SERVER");
                        typedStates.put(type, state);
                    } catch (IllegalArgumentException e) {
                        // 忽略无效的服务器类型
                    }
                });
                
                if (dependencyGraph.canStart(serverType, typedStates)) {
                    if (!startupFutures.containsKey(serverType) || 
                        startupFutures.get(serverType).isDone()) {
                        
                        logger.info("Starting server {} after dependencies are ready", serverType.getName());
                        
                        CompletableFuture<Void> startupFuture = CompletableFuture.runAsync(() -> {
                            startServer(serverType);
                        }, executorService);
                        
                        startupFutures.put(serverType, startupFuture);
                    }
                }
            }
        }
    }
    
    /**
     * 停止所有服务器
     */
    public void stopAllServers() {
        logger.info("Stopping all servers...");
        
        // 按相反顺序停止服务器
        List<ServerType> startupOrder = dependencyGraph.getStartupOrder();
        
        for (int i = startupOrder.size() - 1; i >= 0; i--) {
            ServerType serverType = startupOrder.get(i);
            stopServer(serverType);
        }
        
        // 关闭线程池
        executorService.shutdown();
        try {
            if (!executorService.awaitTermination(10, TimeUnit.SECONDS)) {
                executorService.shutdownNow();
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            executorService.shutdownNow();
        }
        
        logger.info("All servers stopped");
    }
    
    /**
     * 停止单个服务器
     * @param serverType 服务器类型
     */
    private void stopServer(ServerType serverType) {
        logger.info("Stopping server: {}", serverType.getName());
        
        try {
            stateManager.updateServerState(serverType, ServerState.STOPPING);
            
            Object serverBean = stateManager.getServerBean(serverType);
            if (serverBean != null) {
                // 使用反射调用stop方法
                Method stopMethod = serverBean.getClass().getMethod("stop");
                stopMethod.invoke(serverBean);
            }
            
            stateManager.updateServerState(serverType, ServerState.STOPPED);
            logger.info("Server {} stopped successfully", serverType.getName());
            
        } catch (Exception e) {
            logger.error("Failed to stop server: {}", serverType.getName(), e);
            stateManager.updateServerState(serverType, ServerState.ERROR);
        }
    }
}